
	/********************************************************/
	/*                                                      */
	/*                                                      */
	/*         Copyright (C), 1993  SEIKO EPSON Corp.       */
	/*         ALL RIGHTS RESERVED                          */
	/*                                                      */
	/*                                                      */
	/*  file name : _doscan.c                               */
	/*                                                      */
	/*  Revision history                                    */
	/*      93/12/17    first release       K.Shinozuka     */
	/*                                                      */
	/*                                                      */
	/********************************************************/

#ifdef    UNIX
#include    "stdio.h"
#include    "smcvals.h"
#include    "stdarg.h"
#include    "stdlib.h"
#include    "ctype.h"
#include    "limits.h"
#include    "errno.h"
#else
#include    <stdio.h>
#include    <smcvals.h>
#include    <stdarg.h>
#include    <stdlib.h>
#include    <ctype.h>
#include    <limits.h>
#include    <errno.h>
#endif

#define _SHI      'H'
#define _SLO      'L'
#define _SINPSIZ  64              /* the maximum length of input string 
	                                                   of floating point numbers */

extern int _strans( /* _SDAT * */ );
extern int _sint( /* _SDAT * */ );
extern int _sfloat( /* _SDAT * */ );
extern int _sgetc( /* _SDAT * */ );
extern int _sugetc( /* _SDAT *, int */ );

typedef int _SFLGTYP;
typedef struct tgSDat {           /*           data       structure                 */
	    _CODETYP       tdCode;    /* code of input   _STRM (stream) / _STR (string) */
	    unsigned char *ucSrcP;    /* pointer to input stream or string */
	    va_list        tdArgP;    /* the list of a variable number of argument */
	    unsigned char *ucFmtP;    /* pointer to input format */
	    _SFLGTYP       tdCvtFlg;  /* assignment-suppressing flag 
                                                         _SHI (suppress) / _SLO ( assign ) */
	    _SFLGTYP       tdStorFlg; /* assignment flag _SHI ( assigned ) / _SLO ( not done ) */
	    _SFLGTYP       tdErrFlg;  /* input error flag   _SHI ( error ) / _SLO ( no error ) */
	    _SFLGTYP       tdWidFlg;  /* the maximum field width flag
	                                           _SHI ( specified ) / _SLO ( not specified ) */
	    int            iWid;      /* the maximum field width */
	    int            iNum;      /* the number of assigned items */
	    char           cSiz;      /* the size of receiving object */
	 } _SDAT;




int
_doscan( tdSCode, ucSourceP, ucFormatP, tdApP )

	/********************************************************/
	/*                                                      */
	/*  The _doscan function reads formatted data from the  */
	/*  input stream or from the input string, they are     */
	/*  pointed to by fiStrmP. The reading of the input is  */
	/*  controlled by the input format (ucFormatP) which    */
	/*  specifies the input sequences and the conversion    */
	/*  for assignment to the address pointed to by         */
	/*  subsequent arguments.                               */
	/*  If tdSCode is '_STRM', ucSource is a file stream,   */
	/*  otherwise it is a string.                           */
	/*  The format is composed of zero or more directives:  */
	/*  one or more white-space characters; ordinary        */
	/*  single byte characters ( not % ); and conversion    */
	/*  specifications, each of which is started with the   */
	/*  character %.                                        */
	/*  About the specification of the conversion, please   */
	/*  read READMEstdio.                                   */
	/*  The _doscan function returns when the end of the    */
	/*  format string is reached, when the end of the input */
	/*  file is reached, or when the input fails to match   */
	/*  a directives in the format string, whichever occurs */
	/*  first.  If the format is exhausted while arguments  */
	/*  remain, the excess arguments are evaluated but not  */
	/*  converted.                                          */
	/*                                                      */
	/*      RETURN  except EOF  ... the number of input     */
	/*                              items                   */
	/*              EOF         ... If an input failure     */
	/*                              occurs before any       */
	/*                              conversion.             */
	/*                                                      */
	/********************************************************/

    _CODETYP tdSCode         ;   /* type of input source  _STRM (stream) / _STR (string ) */
    unsigned char  *ucSourceP;   /* pointer to input source */
    unsigned char  *ucFormatP;   /* pointer to input format */
    va_list         tdApP    ;   /* pointer to the list of variable numbers of argument */

    {
	 _SDAT          stDat    ;   /* data structure, hold translate data */
	 /*register */int           iInp;        /* input data */
	 /*register */int           iRetVal;     /* return value of _strans */ 


	 /* set data structure */
	 stDat.ucFmtP = ucFormatP;   /* pointer to input format */
	 stDat.tdCode = tdSCode;     /* type of input source */
	 stDat.ucSrcP = ucSourceP;   /* pointer to input source */
	 stDat.tdArgP = tdApP;       /* variable argument */
	 stDat.iNum = 0;             /* the number of input items */
	 stDat.tdErrFlg = _SHI;      /* error flag, input error */

	 iRetVal = 0;
	 do {

	 /* compare input character with format string */
	    while( 1 ) {
	       while( isspace( *stDat.ucFmtP ) ) {    /* skip spaces in input format */
	          ++stDat.ucFmtP;
	       }
	       if( *stDat.ucFmtP == '%' ) {           /* start of conversion */
	          break;
	       } else {
	          if( *stDat.ucFmtP != '\0' ) {       /* not end of input format */
	             while( isspace( iInp = _sgetc( &stDat ) )) {
	                                              /* skip space */
	             }
	             if( iInp != EOF ) {              /* get a character */
	                stDat.tdErrFlg = _SLO;        /* no input error */
	                if( *stDat.ucFmtP == iInp ) { /* check input & format */
	                   ++stDat.ucFmtP;
	                } else {                      /* input doesn't match format */
	                   _sugetc( &stDat, iInp );
	                   break;
	                }
	             } else {                         /* file end or input error */
	                break;
	             }
	          } else {                            /* normal end */
	             stDat.tdErrFlg = _SLO;
	             break;
	          }
	       }
	    }

	    if( *stDat.ucFmtP == '%' ) {              /* start to conversion */
	         ++stDat.ucFmtP;
	    } else {
	      break;
	    }

	 /* get the specification of the conversion */
	    if( *stDat.ucFmtP == '*' ) {              /* character for suppressing */
	       stDat.tdCvtFlg = _SHI;                 /* set suppressing flag */
	       ++stDat.ucFmtP;
	    } else {
	       stDat.tdCvtFlg = _SLO;
	    }

	    stDat.iWid = 0;
	    if( isdigit( *stDat.ucFmtP ) ) {          /* maximum field width */
	       do {
	          stDat.iWid = stDat.iWid * 10 + *stDat.ucFmtP - '0';
	          ++stDat.ucFmtP;
	       } while( isdigit( *stDat.ucFmtP ) );
	       stDat.tdWidFlg = _SHI;                 /* set max. field width flg (data exist) */
	    } else {
	       stDat.tdWidFlg = _SLO;
	    }

	    if( *stDat.ucFmtP == 'h' ) {              /* the size of receiving object */
	       stDat.cSiz = 'h';                      /* short size */
	       ++stDat.ucFmtP;
	    } else if( *stDat.ucFmtP == 'l' ) {
	       stDat.cSiz = 'l';                      /* long size */
	       ++stDat.ucFmtP;
	    } else {
	       stDat.cSiz = ' ';                      /* not specified */
	    }
	
	 /* skip spaces of input */
	    iInp = _sgetc( &stDat );
	    if( *stDat.ucFmtP != 'c' ) {              /* c-conversion doesn't skip spaces */
	       while( isspace( iInp ) ) {             /* skip spaces */
	          iInp = _sgetc( &stDat );
	       }
	    }
	    if( iInp != EOF ) {                       /* file end or input error */
	       stDat.tdErrFlg = _SLO;                 /* not input error */
	    }
	    _sugetc( &stDat, iInp );                  /* put the input character back */

	 /* conversion */
	    iRetVal = _strans( &stDat );
	    if( stDat.tdStorFlg == _SHI ) {           /* conversion and assignment is done */
	       ++stDat.iNum;
	    }

	 } while( iRetVal == 0 );                     /* no conversion error */

	 if( stDat.tdErrFlg != _SHI ) {               /* no input error */
	    return( stDat.iNum );
	 } else {
	    return( EOF );
	 }
    }



int
_strans( stDatP )

	/********************************************************/
	/*                                                      */
	/*  The _strans function reads and converts a string,   */
	/*  and assigns converted input to the object pointed   */
	/*  by the argument list, under control of the data     */
	/*  structure.                                          */
	/*                                                      */
	/*      RETURN  0           ... normal end              */
	/*              EOF         ... Error                   */
	/*                                                      */
	/********************************************************/

	_SDAT        *stDatP        ;   /* data structure */

	{
unsigned char *ucDebug          ;
	 int          iInp          ;   /* input character */
	 unsigned char *ucStorAddP  ;   /* pointer to the store object */

	 stDatP->tdStorFlg = _SLO;             /* reset data-store flag (not stored) */

	 switch( *stDatP->ucFmtP ) {
	    case 'c':
	       if( (stDatP->iWid <= 0) || (stDatP->tdWidFlg == _SLO) ) {
	          stDatP->iWid = 1;                        /* use default value */
	       }
	       if( stDatP->tdCvtFlg == _SLO ) {            /* assignment isn't suppressed */
	          ucStorAddP = va_arg( stDatP->tdArgP, unsigned char * );
	                                                   /* get store address */
	       }
	       for( ; 0 < stDatP->iWid; --(stDatP->iWid) ) { /* until max. field width */
	          iInp = _sgetc( stDatP );
	          if( iInp < 0 ) {                         /* input error */
	             return( EOF );
	          } else if( stDatP->tdCvtFlg == _SLO ) {  /* assignment isn't suppressed */
	             *ucStorAddP = (unsigned char)iInp;
	             ++ucStorAddP;
	             stDatP->tdStorFlg = _SHI;             /* set data-store flag (stored) */
	          }
	       }
	       break;

	    case 's':
	       if( (stDatP->iWid <= 0) || (stDatP->tdWidFlg == _SLO) ) {
	          stDatP->iWid = INT_MAX;                  /* use default value */
	       }
	       if( stDatP->tdCvtFlg == _SLO ) {            /* assignment isn't suppressed */
	          ucStorAddP = va_arg( stDatP->tdArgP, unsigned char * );
	                                                   /* get store address */
	       }
	       for( ; 0 < stDatP->iWid; --(stDatP->iWid)) { /* until max. field width */
	          iInp = _sgetc( stDatP );
	          if( iInp < 0 ) {                         /* input error */
	             *ucStorAddP = '\0';
	             return( EOF );
	          } else if( isspace( iInp ) ) {           /* space */
	             _sugetc( stDatP, iInp );              /* put input character back */
	             break;
	          } else if( stDatP->tdCvtFlg == _SLO ) {  /* assignment isn't suppressed */
	             *ucStorAddP = (unsigned char)iInp;
	             ++ucStorAddP;
	             stDatP->tdStorFlg = _SHI;             /* set data store-flag (stored) */
	          }
	       }
	       if( stDatP->tdCvtFlg == _SLO ) {            /* assignment isn't suppressed */
	           *ucStorAddP = '\0';
	       }
	       break;

	    case 'd': case 'i': case 'o': case 'u': case 'x': case 'X':
	       if( _sint( stDatP ) == EOF ) {              /* conversion failure */
	          return( EOF );
	       }
	       break;

	    case 'e': case 'E': case 'f': case 'g': case 'G':
	       if( _sfloat( stDatP ) == EOF ) {            /* conversion failure */
	          return( EOF );
	       }
	       break;

	    case '%':
	       if( (stDatP->tdCvtFlg != _SLO) || (stDatP->tdWidFlg == _SHI )
	            || (stDatP->cSiz != ' ') ) {          /* error of conversion specifiers */
	          return( EOF );
	       }
	       if( (iInp = _sgetc( stDatP )) != '%' ) {    /* input error */
	          _sugetc( stDatP, iInp );
	          return( EOF );
	       }
	       break;

	    default:                                       /* wrong character */
	       return( EOF );
	       break;
	 }

	 ++(stDatP->ucFmtP);
	 return( 0 );
	} 




int
_sint( stDatP )

	/********************************************************/
	/*                                                      */
	/*  The _sint function converts a string to a integer,  */
	/*  and, assigns the value to the object pointed to by  */
	/*  the argument list, under control of the data        */
	/*  structure.                                          */
	/*                                                      */
	/*      RETURN  0           ... normal end              */
	/*              EOF         ... Error                   */
	/*                                                      */
	/********************************************************/

	_SDAT        *stDatP;  /* data structure */

	{
	 int      iInp       ; /* input character */
	 int      iInp10     ; /* decimal number converted from iInp */
	 int      iSig       ; /* sign data  1 (positive) / -1 (negative) */
	 int      iBase      ; /* the base of the integer */
	 long     lDatVal    ; /* the value of converted integer */
	 _SFLGTYP tdNumFlg   ; /* numerical character flag _SHI (input) / _SLO (no input) */

	 if( (stDatP->iWid <= 0) || (stDatP->tdWidFlg == _SLO) ) {
	    stDatP->iWid = INT_MAX;                       /* use default value */
	 }

	 /* get the sign */
	 iSig = 1;
	 iInp = _sgetc( stDatP ); 
	 switch( iInp ) { 
	    case '+': case '-':
	       if( iInp == '-' ) {
	          iSig = -1;
	       }
	       if( stDatP->iWid <= 1 ) {                  /* field width error */
	          _sugetc( stDatP, iInp );
	          return( EOF );
	       } else {
	          --(stDatP->iWid);
	       }
	       break;

	    default:
	       _sugetc( stDatP, iInp );
	       break;
	 }
	   
	 /* get the base of the integer */
	 switch( *(stDatP->ucFmtP) ) {                     /* initial settlement */
	    case 'o':
	       iBase = 8;
	       break;
	    case 'x': case 'X':
	       iBase = 16;
	       break;
	    default:
	       iBase = 10;
	       break;
	 }

	 tdNumFlg = _SLO;
	 iInp = _sgetc( stDatP ); 
	 if( iInp == '0' ) {                               /* get prefix ? */
	    iInp = _sgetc( stDatP );
	    if( (iInp == 'x') || (iInp == 'X') ) {         /* prefix of hexadecimal ? */
	       if( (*(stDatP->ucFmtP) == 'i') || (*(stDatP->ucFmtP) == 'x')
	          || (*(stDatP->ucFmtP) == 'X' ) ) {       /* hexadecimal integer is specified */
	          iBase = 16;
	          stDatP->iWid = stDatP->iWid -2;
	       } else {                                    /* get 0 as a int value */
	          tdNumFlg = _SHI;
	          _sugetc( stDatP, iInp );
	          --(stDatP->iWid);
	       }
	    } else {
	       if( *(stDatP->ucFmtP) == 'i' ) {            /* octal integer is specified */
	          iBase = 8;
	       }
	       tdNumFlg = _SHI;
	       _sugetc( stDatP, iInp );
	       --(stDatP->iWid);
	    }
	 } else {
	    _sugetc( stDatP, iInp );
	 }

	 /* conversion */
	 lDatVal = 0;
	 while( stDatP->iWid > 0 ) {                       /* until max. field width */
	    iInp = _sgetc( stDatP );

	    if( isxdigit( iInp )) {                        /* hexadecimal number */
	       if( isdigit( iInp ) ) {                     /* decimal number */
	          iInp10 = iInp - '0';
	       } else {
	          if( isupper( iInp ) ) {                  /* A ~ F */
	             iInp10 = 10 + iInp - 'A';
	          } else {
	             iInp10 = 10 + iInp - 'a';
	          }
	       }
	       if( iInp10 < iBase ) {                      /* collect input */
	          lDatVal = iBase * lDatVal + iInp10;
	       } else {
	          _sugetc( stDatP, iInp );
	          break;
	       }
	    } else {
	       _sugetc( stDatP, iInp );
	       break;
	    }
	    tdNumFlg = _SHI;                               /* get numeric character */
	    --(stDatP->iWid);
	 }
	 if( tdNumFlg  == _SLO ) {                         /* no numeric character */
	    return( EOF );
	 }

	 /* assignment */
	 if( stDatP->tdCvtFlg == _SLO ) {                  /* assignment isn't suppressed */
	    if( stDatP->cSiz == 'h' ) {                    /* short int */
	       *(va_arg( stDatP->tdArgP, short * )) = (short)( iSig * lDatVal );
	    } else if( stDatP->cSiz == 'l' ) {             /* long int */
	       *(va_arg( stDatP->tdArgP, long * )) = (long)( iSig * lDatVal );
	    } else {                                       /* int */
	       *(va_arg( stDatP->tdArgP, int * )) = (int)( iSig * lDatVal );
	    }
	    stDatP->tdStorFlg = _SHI;                      /* set data-store flag (stored) */
	 }

	 return( 0 );
	}






int
_sfloat( stDatP )

	/********************************************************/
	/*                                                      */
	/*  The _sfloat function converts a string to a         */
	/*  floating-point number, and assigns the value to the */
	/*  object pointed to by the argument list, under       */
	/*  control of the data structure.                      */
	/*                                                      */
	/*      RETURN  0           ... normal end              */
	/*              EOF         ... Error                   */
	/*                                                      */
	/********************************************************/

	_SDAT    *stDatP     ;   /* data structure */

	{
	 int      iInp       ;   /* input character */
	 int      iErrNo     ;   /* errno */
	 double   dVal       ;   /* the value of floating point number */
	 _SFLGTYP tdSigFlg   ;   /* sign flag _SHI (input) / _SLO (no input) */
	 _SFLGTYP tdNumFlg   ;   /* numerical character flag _SHI (input) / _SLO (no input) */
	 _SFLGTYP tdPntFlg   ;   /* decimal point flag _SHI (input) / _SLO (no input) */
	 char    *cStorAddP  ;   /* to be used to access CInpStrP[ ] */
	 char     CInpStrP[ _SINPSIZ + 1 ];  /* store array of input string */

	 if( (stDatP->iWid <= 0) || (stDatP->tdWidFlg == _SLO)
	      || (stDatP->iWid > _SINPSIZ) ) {
	    stDatP->iWid = _SINPSIZ;                      /* use default value */
	 }

	 /* input of fractional part */
	 tdNumFlg = _SLO;
	 tdPntFlg = _SLO;
	 cStorAddP = CInpStrP;

	 iInp = _sgetc( stDatP );
	 if( (iInp == '+') || (iInp == '-' ) ) {          /* input of sign */
	    *cStorAddP = iInp;
	    ++cStorAddP;
	    --(stDatP->iWid);                             /* renewal of field width data */
	 } else {
	    _sugetc( stDatP, iInp );
	 }

	 while( stDatP->iWid > 0 ) {                      /* until max. field width */
	    iInp = _sgetc( stDatP ); 
	    if( isdigit( iInp ) ) {                       /* decimal number */
	       tdNumFlg = _SHI;
	    } else {
	       if( (iInp == '.') && (tdPntFlg == _SLO) ) { /* first decimal point */
	          tdPntFlg = _SHI;
	       } else {
	          _sugetc( stDatP, iInp );
	          break;
	       }
	    }
	    *cStorAddP = iInp;
	    ++cStorAddP;
	    --(stDatP->iWid);
	 }
	
	 if( tdNumFlg == _SLO ) {                         /* input error */
	    return( EOF );
	 }

	 /* input of exponential part */
	 if( stDatP->iWid > 0 ) {                         /* not max. field width */
	    iInp = _sgetc( stDatP );
	    if( (iInp == 'e') || (iInp == 'E') ) {        /* input of exponential part */
	       tdNumFlg = _SLO;                           /* initialization of flags */
	       tdSigFlg = _SLO;
	       *cStorAddP = iInp;
	       ++cStorAddP;
	       --(stDatP->iWid);

	       while( stDatP->iWid > 0 ) {                /* until max. field width */
	          iInp = _sgetc( stDatP );
	          if( isdigit( iInp ) ) {                 /* decimal number */
	             tdNumFlg = _SHI;
	          } else {
	             if( ((iInp == '+') || (iInp == '-')) && (tdNumFlg == _SLO)
	                  && (tdSigFlg == _SLO) ) {       /* first sign */
	                tdSigFlg = _SHI;
	             } else {
	                _sugetc( stDatP, iInp );
	                break;
	             }
	          }
	          *cStorAddP = iInp;
	          ++cStorAddP;
	          --(stDatP->iWid);                        /* renewal of field width data */
	       }	
	    } else {
	       _sugetc( stDatP, iInp );
	    }
	 }
	 *cStorAddP = '\0';

	 if( tdNumFlg == _SLO ) {                          /* input error */
	    return( EOF );
	 }

	 /* assignment */
	 if( stDatP->tdCvtFlg == _SLO ) {                  /* assignment isn't suppressed */
	    iErrNo = errno;                                /* temporary store */
	    dVal = strtod( CInpStrP, NULL );               /* conversion to double */
	    if( stDatP->cSiz == 'l' ) {                    /* double */
	       *(va_arg( stDatP->tdArgP, double * )) = dVal;
	    } else {                                       /* float */
	       *(va_arg( stDatP->tdArgP, float * )) = dVal;
	    }
	    errno = iErrNo;                                /* get errno back */
	    stDatP->tdStorFlg = _SHI;                      /* set data store flag (store) */
	 }

	 return( 0 );
	}
	






int
_sgetc( stDatP )

	/********************************************************/
	/*                                                      */
	/*  The _sgetc function get the next character as an    */
	/*  unsigned char converted to an int, form the input   */
	/*  stream or string, according to the data structure.  */
	/*  In the case of string, the pointer to the string is */
	/*  put forward.                                        */
	/*                                                      */
	/*      RETURN  except EOF  ... the next character      */
	/*              EOF         ... Error                   */
	/*                                                      */
	/********************************************************/

	_SDAT         *stDatP   ;     /* data structure */

	{
	 int           iInp     ;     /* input character converted from an unsigned char */
	 unsigned char ucDat    ;     /* buffer for input */
	 FILE         *fiStrmP  ;     /* input file stream */

	 if( stDatP->tdCode == _STRM ) {                /* input from the input stream */
	    fiStrmP = (FILE *)( stDatP->ucSrcP );
	    if( fiStrmP->_flg == _UGETY){               /* exist unget character */
	       fiStrmP->_flg = _UGETN;                  /* clear unget character */
	       iInp = (int)( fiStrmP->_buf );           /* set unget data */
	    } else {                                    /* read a data from stdin */
	       if( read( fiStrmP->_fd, &ucDat, 1) != 1 ){
	          return   EOF;                         /* read error */
	       } else {
	           iInp =  (int)ucDat;                  /* set read character */
	       }
	    }
	 } else { 
	    if( (iInp = *(stDatP->ucSrcP)) == '\0' ) {  /* end of string */
	       iInp = EOF;
	    } else {
	       ++(stDatP->ucSrcP);
	    }
	 }

	 return( iInp );
	}






int
_sugetc( stDatP, iCh )

	/********************************************************/
	/*                                                      */
	/*  The _sugetc function pushes the character specified */
	/*  by iCh ( converted to unsigned char ) back onto the */
	/*  input stream or input string.                       */
	/*  If stream is specified in data structure, the buffer*/
	/*  of the stream for ungetc must be empty. Otherwise,  */
	/*  _sungetc fails and return EOF.                      */
	/*                                                      */
	/*      RETURN  except EOF  ... the character           */
	/*                                pushed back           */
	/*              EOF         ... Error                   */
	/*                                                      */
	/********************************************************/

	_SDAT      *stDatP   ;           /* data structure */
	int         iCh      ;           /* character to be pushed back */


	{
	 FILE      *fiStrmP  ;           /* input file stream */

	 if( stDatP->tdCode == _STRM ) {           /* push back to the input stream */
	    fiStrmP = (FILE *) ( stDatP->ucSrcP );
        if(fiStrmP->_flg == _UGETY){ 
           return   EOF;                       /* unget character exist */
        }
        else {                                 /* pushed back character */
           fiStrmP->_buf = (unsigned char)iCh;
           fiStrmP->_flg = _UGETY;
        }
	 } else { 
	    --(stDatP->ucSrcP);
	 }

	 return( iCh );
	}
